﻿using System;
using System.Collections.Generic;
using GameFramework.Battle.Core;
using Gameplay.PVE.Utils;
using ParadoxNotion;
using RootMotion.FinalIK;
using UnityEngine;
using UnityEngine.Profiling;
using Yoozoo.Libs;
using Yoozoo.Managers;

namespace Gameplay.PVE.Survivor
{
    public class Bullet : IClass
    {
        public int indexInArray;
        private BulletMovement movement;
        private BulletRenderer renderer;
        
        //public SkillBase sourceSkill;
        public BulletSpawner sourceSpawner;
        public BattleUnit sourceUnit;

        public EBattleSkillType sourceSkillType;
        
        private Dictionary<int, float> hitUnit = new Dictionary<int, float>();
        private bool hasHit = false;

        public int fixedDamage = 0;
        public Vector3 Position
        {
            set
            {
                position = value;
                renderer?.SetPosition(value);
            }
            get
            {
                return position;
            }
        }

        private Vector3 position;
        private Vector3 forward;

        public Vector3 Forward
        {
            set
            {
                forward = value;
                renderer.SetForward(value);
            }
            get
            {
                return forward;
            }
        }

        public BulletConfig config;
        private bool isInHand;
        private float leaveHandTime;
        public int pointIndex;
        public bool isCritical;

        private float startTime;

        private float externalSpeed = -1;

        public float speed
        {
            get
            {
                if (externalSpeed >= 0)
                {
                    return externalSpeed;
                }
                return config.speed;
            }
        }

        public void SetExternalSpeed(float speed)
        {
            externalSpeed = speed;
        }
        
        public void Initialize(BulletConfig config,BulletSpawner sourceSpawner, BattleUnit sourceUnit)
        {
            isCritical = BattleHelper.GetRandomValue(sourceUnit.criticalRate);
            this.config = config;
            this.sourceSpawner = sourceSpawner;
            this.sourceUnit = sourceUnit;
            movement.Initialize(this);
            renderer = ClassManager.Get<BulletRenderer>();
            renderer.Initialize(config);
            isInHand = false;
            hasHit = false;
            if (config.in_hand_frame > 0)
            {
                isInHand = true;
                leaveHandTime = TimeManager.time + config.in_hand_frame / 30f;
                renderer.SetParent(sourceUnit.GetGunPoint(pointIndex));
                renderer.SetPosition(sourceUnit.GetGunPoint(pointIndex).position);
            }

            startTime = TimeManager.time;
        }
        
        
        public SkillTarget target;
        public Vector3 targetPosition;
        
        public void SetTarget(SkillTarget target)
        {
            if (!target.isValid)
            {
                BattleDebug.LogError("target is notvalid");
            }
            this.target = target;
            targetPosition = target.GetTargetPosition();
        }

        public void SetTargetPosition(Vector3 position)
        {
            this.targetPosition = position;
        }
        
        public void SetStartPosition(Vector3 position)
        {
            this.Position = position;
            movement.SetPosition(position);
        }
        

        public void Update()
        {
            if (isInHand)
            {
                if (TimeManager.time >= leaveHandTime)
                {
                    renderer.SetParent(SurvivorManager.Instance.Root);
                    this.movement.Start();
                    isInHand = false;
                }
                position = renderer.GetPosition();
            }
            else
            {
                if (BattleDebug.enableProfiler)
                {
                    Profiler.BeginSample("Bullet.Update." + movement.GetType().Name);
                }
                movement.Update();
                if (BattleDebug.enableProfiler)
                {
                    Profiler.EndSample();
                }
            }
        }

        public void Dispose()
        {
            if (renderer != null)
            {
                renderer.Dispose();
                ClassManager.Free(renderer);
                renderer = null;
            }

            if (movement != null)
            {
                ClassManager.Free(movement);
                movement = null;
            }
            if (config.destroy_effect_id > 0)
            {
                BattleEffectManager.Instance.CreateEffectAutoDispose(config.destroy_effect_id, position, forward);
            }
            hitUnit.Clear();

            if (config.destroy_bullets != null)
            {
                for (int i = 0; i < config.destroy_bullets.Count; i++)
                {
                    var bulletConfig = BattleConfigManager.Instance.GetBulletConfig(config.destroy_bullets[i]);
                    if (bulletConfig != null)
                    {
                        var bullet = BulletManager.Instance.CreateBullet(bulletConfig);
                        if (bullet != null)
                        {
                            bullet.Initialize(bulletConfig,sourceSpawner,this.sourceUnit);
                            bullet.SetStartPosition(Position);
                            bullet.SetTargetPosition(Position);
                            bullet.Start();
                        }
                    }
                }
            }
            externalSpeed = -1;
        }

        public bool NeedDispose()
        {
            if (movement.useMovementLifeTime)
            {
                return movement.IsEnd();
            }
            if (movement.IsEnd())
            {
                return true;
            }
            if (config.destroy_type == (int)EBulletDestroyType.OnTime)
            {
                return TimeManager.time - startTime > config.destroy_param;
            }
            else if (config.destroy_type == (int)EBulletDestroyType.OnHit)
            {
                return hasHit;
            }
            return false;
        }

        public void SetMovement(BulletMovement movement)
        {
            this.movement = movement;
        }

        public void Start()
        {
            if (isInHand)
            {
                return;
            }
            this.movement.Start();
        }

        public void OnHit(BattleUnit target)
        {
            Vector3 hitPosition = target.Position;
            //是否再CD中
            if (config.collision_cd > 0)
            {
                if (hitUnit.TryGetValue(target.unitId, out var time))
                {
                    if (TimeManager.time - time < config.collision_cd)
                    {
                        return;
                    }
                }
                hitUnit[target.unitId] = TimeManager.time;
            }
            
            //产生元素
            for (int i = 0; i < config.elements.Count; i++)
            {
                target.AddElement(config.elements[i],sourceUnit,this);
            }
            //创建特效
            if (isCritical && config.critical_effect_id > 0)
            {
                var point = target.GetHitPoint(0);
                var forward = this.forward;
                forward.y = 0;
                BattleEffectManager.Instance.CreateEffectAutoDispose(config.critical_effect_id, point.position, forward);
            }
            else if (config.hit_effect_id > 0)
            {
                var point = target.GetHitPoint();
                if (point == null)
                {
                    BattleDebug.LogError(target.unitId + " " + sourceUnit.unitId + target.isDead);
                }
                else
                {
                    BattleEffectManager.Instance.CreateEffectAutoDispose(config.hit_effect_id, point.position, forward);
                }
            }

            movement?.OnHit(hitPosition);
            hasHit = true;
        }
        
        public void HitByCollision()
        {
            /*if (config.shape_type == (int)EBulletShapeType.Circle)
            {
                var radius = config.shape_params[0];
                var targetList = UnitManager.Instance.GetTargetsByCircle(Position,radius,sourceSkill.GetTargetTeam());
                for (int i = 0; i < targetList.Count; i++)
                {
                    OnHit(targetList[i]);
                }
            }*/
            if (config.shape_type == 0)
            {
                return;
            }
            var targetTeam = sourceSpawner.GetTargetTeam();
            //需要增加中立阵营
            targetTeam = targetTeam | BattleHelper.GetTeamMask(1);
            var targetList = GetHitList(position,forward,config.shape_type,config.GetShapeParam(0),config.GetShapeParam(1));
            for (int i = 0; i < targetList.Count; i++)
            {
                var unit = UnitManager.Instance.GetUnitById(targetList[i]);
                if (unit != null && !unit.isDead && BattleHelper.IsTeamMatch(unit.team,targetTeam))
                {
                    OnHit(unit);
                }
            }
        }

        private List<int> GetHitList(Vector3 position,Vector3 forward,int shapeType,float param1,float param2 = 0)
        {
            position.y = sourceUnit.Position.y;
            forward.y = 0;
            var targetList = CollisionManager.Instance.GetCollisionGroup(position,forward,shapeType,param1,param2);
            if (SurvivorManager.showCollision)
            {
                CollisionManager.Instance.ShowBulletCollision(this,targetList,position, forward, config.shape_type,
                    config.GetShapeParam(0), config.GetShapeParam(1));
            }
            return targetList;
        }

        public void HitByTrail(Vector3 startPosition,Vector3 endPosition)
        {
            var targetTeam = sourceSpawner.GetTargetTeam();
            //需要增加中立阵营
            targetTeam = targetTeam | BattleHelper.GetTeamMask(1);
            var width = config.GetShapeParam(0);
            if (config.shape_type == (int)EBulletShapeType.Circle)
            {
                width = width * 2;
            }
            var targetList = GetHitList(startPosition,endPosition - startPosition, (int)EBulletShapeType.Rect,width,Vector3.Distance(startPosition,endPosition));
            for (int i = 0; i < targetList.Count; i++)
            {
                var unit = UnitManager.Instance.GetUnitById(targetList[i]);
                if (unit != null && !unit.isDead && BattleHelper.IsTeamMatch(unit.team,targetTeam))
                {
                    OnHit(unit);
                }
            }
        }

        public void OnReset()
        {
            renderer = null;
            movement = null;
            fixedDamage = 0;
            isInHand = false;
            hitUnit.Clear();
            hasHit = false;
            externalSpeed = -1;
        }
    }
}
